using System;
using System.Diagnostics;

namespace BehaveSharp
{
    public delegate void Action();
    // public delegate void Action<T>(T obj); -- Already defined in mscorlib
    public delegate void Action<TArg0, TArg1>(TArg0 arg0, TArg1 arg1);
    public delegate void Action<TArg0, TArg1, TArg2>(TArg0 arg0, TArg1 arg1, TArg2 arg2);
    public delegate void Action<TArg0, TArg1, TArg2, TArg3>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3);

    public class Scenario
    {
        private const string GivenType = "\t\tGiven";
        private readonly Story _story = null;
        private readonly string _title = null;
        private bool _isBlank;

        internal Scenario(string title, Story story)
        {
            Debug.Assert(story != null);

            _title = title;
            _story = story;
            _isBlank = true;
        }

        public string Title
        {
            get { return _title; }
        }

        internal Story Story
        {
            get { return _story; }
        }

        private void AddBlankMessage()
        {
            if (!_isBlank)
            {
                _story.AddMessage("");
            }

            _isBlank = false;
        }

        public GivenFragment Given(string context, Action action)
        {
            AddBlankMessage();

            _story.InvokeAction(GivenType, context, action);

            return new GivenFragment(this);
        }

        public GivenFragment Given<TArg0>(string context, TArg0 arg0, Action<TArg0> action)
        {
            AddBlankMessage();

            _story.InvokeAction(GivenType, context, action, arg0);

            return new GivenFragment(this);
        }

        public GivenFragment Given<TArg0, TArg1>(string context, TArg0 arg0, TArg1 arg1, Action<TArg0, TArg1> action)
        {
            AddBlankMessage();

            _story.InvokeAction(GivenType, context, action, arg0, arg1);

            return new GivenFragment(this);
        }

        public GivenFragment Given<TArg0, TArg1, TArg2>(string context, TArg0 arg0, TArg1 arg1, TArg2 arg2, Action<TArg0, TArg1, TArg2> action)
        {
            AddBlankMessage();

            _story.InvokeAction(GivenType, context, action, arg0, arg1, arg2);

            return new GivenFragment(this);
        }

        public GivenFragment Given<TArg0, TArg1, TArg2, TArg3>(string context, TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, Action<TArg0, TArg1, TArg2, TArg3> action)
        {
            AddBlankMessage();

            _story.InvokeAction(GivenType, context, action, arg0, arg1, arg2, arg3);

            return new GivenFragment(this);
        }

        public GivenFragment Given(string context)
        {
            AddBlankMessage();

            _story.InvokeActionFromCatalog(GivenType, context);

            return new GivenFragment(this);
        }

        public GivenFragment Given<TArg0>(string context, TArg0 arg0)
        {
            AddBlankMessage();

            _story.InvokeActionFromCatalog(GivenType, context, arg0);

            return new GivenFragment(this);
        }

        public GivenFragment Given<TArg0, TArg1>(string context, TArg0 arg0, TArg1 arg1)
        {
            AddBlankMessage();

            _story.InvokeActionFromCatalog(GivenType, context, arg0, arg1);

            return new GivenFragment(this);
        }

        public GivenFragment Given<TArg0, TArg1, TArg2>(string context, TArg0 arg0, TArg1 arg1, TArg2 arg2)
        {
            AddBlankMessage();

            _story.InvokeActionFromCatalog(GivenType, context, arg0, arg1, arg2);

            return new GivenFragment(this);
        }

        public GivenFragment Given<TArg0, TArg1, TArg2, TArg3>(string context, TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3)
        {
            AddBlankMessage();

            _story.InvokeActionFromCatalog(GivenType, context, arg0, arg1, arg2, arg3);

            return new GivenFragment(this);
        }
    }
}
